#LogPlayer is designed to emulate the logging functionality in the LOTRO game client to debug applications which depend on the log file and timing, 
# it enables a user to replay a log file with lines added at the same intervals as the game client did at recording time.

from datetime import datetime
import json
import glob
import sys
import getopt
import os
import time
import codecs
from msvcrt import getch
from win32com.shell import shell

verbose = False

class LotroLog:
	"""A collection of lotro log lines representing a whole lotro log file"""
	def __init__(self):
		self.lotrologlines = []
	
	def openinput(self, filename):
		try:
			input_file = codecs.open(filename, "r", "utf-8")
		except IOError:
			print "Error opening file " + filename + ", exiting!"
			sys.exit(2)
		return input_file
		
	def openoutput(self, filename):
		try:
			output_file = codecs.open(filename, "w", "utf-8")
		except IOError:
			print "Error opening file " + filename + ", exiting!"
			sys.exit(2)
		return output_file
	
	def findlatestfile(self, path, pattern):
		folder_listing = glob.glob(path + "\\" + pattern)
		if not folder_listing:
			print "No log file found matching specified parameters, exiting"
			sys.exit(2)
		return folder_listing.pop()
	
	def getlinecount(self):
		return len(self.lotrologlines)
	
	def getlines(self,start,end):
		return self.lotrologlines[start,end]
	
	def parsenewlines(self, filehandle):
		while True:
			new_line = filehandle.readline()
			if len(new_line) ==0:
				break # End of file
			#datestamp = datetime.now().isoformat() # does not work because when microsecond is 0 the resolution is skipped so strings differ
			datestamp = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
				
			self.lotrologlines.append([datetime.now().isoformat(), new_line])
			if verbose:
					print new_line
	
	def write(self, filehandle):
		json.dump(self.lotrologlines, filehandle, sort_keys=True, indent=4)
		filehandle.close()
	
	def read(self, filehandle):
		self.lotrologlines = json.load(filehandle)

def main():
	try:
		opts, args = getopt.getopt(sys.argv[1:], "hi:o:rpv", ["help", "input=", "output=", "record", "play", "verbose"])
	except getopt.GetoptError, err:
		# print help information and exit:
		print str(err) # will print something like "option -a not recognized"
		usage()
		sys.exit(2)
	output = None
	record = False
	play = False
	input = ""
	output = ""
	for o, a in opts:
		if o in ("-v", "--verbose"):
			global verbose
			verbose = True
		elif o in ("-h", "--help"):
			usage()
			sys.exit()
		elif o in ("-i", "--input"):
			input = a
		elif o in ("-o", "--output"):
			output = a
		elif o in ("-r", "--record"):
			if play == True:
				multiple_exclusive_options()
			record = True
		elif o in ("-p", "--play"):
			if record == True:
				multiple_exclusive_options()
			play = True
		else:
			assert False, "unhandled option"
	if True not in (record, play):
		print "play/record not specied, recording most recent lotro log file"
		record = True
	
	if record == True:
		print "recording lotro log file, use ctrl-c to stop recording and save data"
		mylog=LotroLog()
		if input:
			logfile = mylog.openinput(input)
		else:
			#Default lotro directory, user home dir plus the lotro defaults
			input = mylog.findlatestfile(get_lotro_log_dir(), "Combat_*.txt")
			logfile = mylog.openinput(input)
		
		while True:
			try:
				mylog.parsenewlines(logfile)
				time.sleep(0.01)
			except KeyboardInterrupt:
				print "Keyboard Interrupt received, writing log and exiting"
				if output:
					jsonfile = mylog.oopenoutput(output)
				else:
					jsonfile = mylog.openoutput(input + ".json")
					
				mylog.write(jsonfile)
				sys.exit()
	
	if play == True:
		print "playing back lotro log file, use ctrl-c to stop playback"
		mylog=LotroLog()
		
		if input:
			jsonfile = mylog.openinput(input)
		else:
			#Default lotro directory, user home dir plus the lotro defaults
			input = mylog.findlatestfile(get_lotro_log_dir(), "Combat_*.txt.json")
			jsonfile = mylog.openinput(input)
		
		if output:
			logfile = mylog.openoutput(output + ".tmp")
		else:
			tmplogfilename = input.split(".json")[0]
			if tmplogfilename == input:
				tmplogfilename = input + ".txt" + ".tmp"
			logfile = mylog.openoutput(tmplogfilename)
		
		mylog.read(jsonfile)
		
		lasttimestamp = datetime.strptime(mylog.lotrologlines[0][0], "%Y-%m-%dT%H:%M:%S.%f")
		for logentry in mylog.lotrologlines:
			try:
				logfile.write(logentry[1])
				logfile.flush()					
				timestamp = datetime.strptime(logentry[0], "%Y-%m-%dT%H:%M:%S.%f")
				delta = timestamp-lasttimestamp
				if verbose:
					print logentry[1]
					if (delta.seconds > 10):
						print "----------- Sleeping for " + str(delta.seconds) + " seconds ----------" 
				time.sleep(delta.seconds + delta.microseconds/1000000)
				lasttimestamp = timestamp
			except KeyboardInterrupt:
				print "Keyboard Interrupt received, stopping playback"
				print "Press X to exit or S to skip to next log entry"
				while True:
					keypress = getch()
					if keypress in ("X", "x"):
						sys.exit()
					elif keypress in ("S", "s"):
						lasttimestamp = timestamp
						break
					else:
						print "Invalid key pressed, please press either X or S"

def multiple_exclusive_options():
	print "options -p (--play) and -r (--record) can not be used simultaneously"
	usage()
	sys.exit(2)
	
def get_lotro_log_dir():
	df = shell.SHGetDesktopFolder()
	pidl = df.ParseDisplayName(0, None,  
    "::{450d8fba-ad25-11d0-98a8-0800361b1103}")[1]
	return shell.SHGetPathFromIDList(pidl) + "\The Lord of the Rings Online"

def usage():
	print "	Usage for Record: " + sys.argv[0] + " -r [-i LOG_FILE] [-o JSON_OUTPUT_FILE]"
	print "	Usage for Play: " + sys.argv[0] + " -p -i JSON_INPUT_FILE -o LOG_FILE"
	print "	 -r --record			monitor log file from lotro and timestamp entries, record this to a file"
	print "	 -p --play			append log entries to log file at time intervals given by timestamps"
	print "	 -i --input  [INPUT_FILE]	input file, if recording this is the lotro log file, if playing this is the json file with logs and timestamps"
	print "	 -o --output [OUTPUT_FILE]	output file, if recording this is the json fiel with timestamps, if playing this is the fake lotro log"
	print "	 -v --verbose			prints debugging information and extra processing data"
	print "	Please select either play or record, only one of those options is allowed"
	print "	If no filenames are specified the program fill attempt to find the lotro directory and use it for all actions"

if __name__ == "__main__":
	main()